package com.wh.wisdomsite.xbox.server.manager;


import com.wh.wisdomsite.xbox.common.XboxRequestContext;
import com.wh.wisdomsite.xbox.core.security.InvokeTimesController;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;


/**
 * 声明控制对服务访问和调用的次数,频率接口(业务接口实现类)
 * @Package com.wh.wisdomsite.xbox.core.security
 * @author 谢泽鹏
 * @date 2014年10月8日 下午4:02:14
 * @Copyright 个人版权所有
 * @Company 贵州万华科技有限公司Copyright (c) 2014
 * @version V1.0
 */
public class SampleInvokeTimesController implements InvokeTimesController {

    private static final Log logger = LogFactory.getLog(SampleInvokeTimesController.class);

    //TODO  集群环境下应该使用memcached记录 appCallCounter
    //应用访问次数限制
    private static Map<String, AtomicInteger> appCallLimits;

    //应用访问次数记录
    private static Map<String, AtomicInteger> appCallCounter;

    //应用方法请求次数记录
    private static Map<String, AtomicInteger> appMethodCallCounter;

    //应用方法请求次数限制
    private static Map<String, AtomicInteger> appMethodCallLimit;

    //app下方法请求记录，只记录最近一分钟内的请求时间
    private static Map<String, ArrayList<AtomicLong>> appMethodCallRecord;

    //app下方法的请求频率，每个key(app与方法组合)每分钟请求的次数
    private static Map<String, AtomicInteger> appMethodCallRate;

    static {
        appCallCounter = new ConcurrentHashMap<String, AtomicInteger>();
        appMethodCallCounter = new ConcurrentHashMap<String, AtomicInteger>();
        appMethodCallRecord = new ConcurrentHashMap<String, ArrayList<AtomicLong>>();
    }

    /**
     * 计算应用、会话及用户服务调度总数
     *
     * @param xrc
     */
    @Override
    public void caculateInvokeTimes(XboxRequestContext xrc) {
        if (xrc.isSuccess()) {
            //应用请求总数 + 1
            if (!appCallCounter.containsKey(xrc.getAppKey())) {
                appCallCounter.put(xrc.getAppKey(), new AtomicInteger(1));
            } else {
                appCallCounter.get(xrc.getAppKey()).incrementAndGet();
            }

            //应用方法请求总数 + 1
            String appMethod = getAppMethod(xrc);
            if (!appMethodCallCounter.containsKey(appMethod)) {
                appMethodCallCounter.put(appMethod, new AtomicInteger(1));
            } else {
                appMethodCallCounter.get(appMethod).incrementAndGet();
            }
        }
    }


    /**
     * *
     * 户服务访问次数是否超限
     * @param xrc
     * @return
     */
    @Override
    public boolean isUserInvokeLimitExceed(XboxRequestContext xrc) {
        return false;
    }


    /**
     * 某个会话的服务访问次数是否超限
     *
     * @param xrc
     * @return
     */
    @Override
    public boolean isSessionInvokeLimitExceed(XboxRequestContext xrc) {
        return false;
    }


    /**
     * *
     * 应用的服务访问次数是否超限
     *
     * @param xrc
     * @return
     */
    @Override
    public boolean isAppInvokeLimitExceed(XboxRequestContext xrc) {
        //如果limit中不存在对应的appkey，则不能访问
        if (!appCallLimits.containsKey(xrc.getAppKey())) {
            return true;
        }
        if (null == appCallCounter.get(xrc.getAppKey())) {
            return false;
        }
        //如果limit中对应的次数为0，则不限制次数
        if (appCallLimits.get(xrc.getAppKey()).intValue() == 0) {
            return false;
        }
        return appCallCounter.get(xrc.getAppKey()).intValue() > appCallLimits.get(xrc.getAppKey()).intValue();

    }


    /**
     * *
     * 应用对服务的访问频率是否超限
     * @param xrc
     * @return
     */
    @Override
    public boolean isAppInvokeFrequencyExceed(XboxRequestContext xrc) {
        return false;
    }


    /**
     * 应用对服务方法访问次数是否超限
     * @param xrc
     * @return
     */
    @Override
    public boolean isMethodInvokeLimitExceed(XboxRequestContext xrc) {
        String appMethod = getAppMethod(xrc);
        //map中不存在appMethod，则不能访问
        if (!appMethodCallLimit.containsKey(appMethod)) {
            return true;
        }
        if (null == appMethodCallCounter.get(appMethod)) {
            return false;
        }
        //没有限制
        if (appMethodCallLimit.get(appMethod).intValue() == 0) {
            return false;
        }
        return appMethodCallCounter.get(appMethod).intValue() > appMethodCallLimit.get(appMethod).intValue();

    }


    /**
     * *
     * 应用对服务方法的访问频率是否超限
     * @param xrc
     * @return
     */
    @Override
    public boolean isMethodInvokeFrequencyExceed(XboxRequestContext xrc) {

//        //应用+方法+版的组成的key
//        String appMethod = getAppMethod(xrc);
//        //1。获取请求时间记录列表
//        ArrayList<Long> recordList = appMethodCallRecord.get(appMethod);
//        //首次请求
//        if(null == recordList){
//            recordList = new ArrayList<Long>();
//            //记录下当前请求的时间
//            recordList.add(System.currentTimeMillis());
//            appMethodCallRecord.put(appMethod,recordList);
//        }else{
//            //非首次请求
//            Long currentMillis = System.currentTimeMillis();
//            //如果当前时间减去集合中第一个记录的时间大于1分钟，则要删除掉，只保留一分名钟之内的记录
//            while (recordList.size() > 0 && currentMillis - recordList.get(0) > 1000*60){
//                recordList.remove(0);
//            }
//
//            //然后再判断剩下的记录有没有超出频率范围
//            if(null != appMethodCallRate.get(appMethod)){
//                if(appMethodCallRate.get(appMethod)!=0 && recordList.size() >= appMethodCallRate.get(appMethod)){
//                    //超出频率
//                    return true;
//                }else{
//                    recordList.add(currentMillis);
//                    appMethodCallRecord.put(appMethod,recordList);
//                }
//            }else{
//                //没有频率计录
//                return true;
//            }
//
//        }

        return false;
    }

    public Map<String, AtomicInteger> getAppCallLimits() {
        return appCallLimits;
    }

    public void setAppCallLimits(Map<String, AtomicInteger> appCallLimits) {
        SampleInvokeTimesController.appCallLimits = appCallLimits;
    }

    public Map<String, AtomicInteger> getAppMethodCallLimit() {
        return appMethodCallLimit;
    }

    public void setAppMethodCallLimit(Map<String, AtomicInteger> appMethodCallLimit) {
        SampleInvokeTimesController.appMethodCallLimit = appMethodCallLimit;
    }

    public Map<String, AtomicInteger> getAppMethodCallRate() {
        return appMethodCallRate;
    }

    public void setAppMethodCallRate(Map<String, AtomicInteger> appMethodCallRate) {
        SampleInvokeTimesController.appMethodCallRate = appMethodCallRate;
    }


    public static void resetAppCallCounter(String key) {
        appCallCounter.put(key, new AtomicInteger(0));
    }

    public static void resetAppMethodCallCounter(String key) {
        appMethodCallCounter.put(key, new AtomicInteger(0));
    }


    public static String getAppMethod(XboxRequestContext xrc) {
        return xrc.getAppKey() + "$" + xrc.getMethod() + "$" + xrc.getVersion();
    }
}

